import React, { useRef, useEffect, useState } from 'react';
import styled from 'styled-components';
import * as THREE from 'three';
import { OrbitControls } from 'three/addons/controls/OrbitControls.js';

const EarthContainer = styled.div`
  flex: 1;
  position: relative;
  background: #000;
`;

const Canvas = styled.canvas`
  width: 100%;
  height: 100%;
`;

const CountryInfoPanel = styled.div`
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  background: rgba(0, 20, 40, 0.9);
  border: 2px solid rgba(0, 255, 255, 0.6);
  border-radius: 8px;
  padding: 20px;
  color: white;
  min-width: 300px;
  max-width: 500px;
  z-index: 1000;
  box-shadow: 0 0 20px rgba(0, 255, 255, 0.4);
`;

const CountryTitle = styled.h2`
  color: white;
  font-size: 24px;
  margin-bottom: 15px;
  text-align: center;
  border-bottom: 1px solid rgba(0, 255, 255, 0.4);
  padding-bottom: 10px;
`;

const CountryInfo = styled.div`
  margin-bottom: 15px;
`;

const CountryValue = styled.div<{ color: string }>`
  font-size: 28px;
  font-weight: bold;
  color: ${props => props.color};
  text-align: center;
  margin: 15px 0;
`;

const CloseButton = styled.button`
  background: rgba(0, 255, 255, 0.2);
  border: 1px solid rgba(0, 255, 255, 0.6);
  color: white;
  padding: 8px 16px;
  border-radius: 4px;
  cursor: pointer;
  display: block;
  margin: 20px auto 0;
  font-size: 16px;
  transition: all 0.2s;
  
  &:hover {
    background: rgba(0, 255, 255, 0.4);
  }
`;

interface Marker {
  lat: number;
  lng: number;
  size: number;
  color: string;
  name: string;
  country: string;
  value: number;
  description: string;
}

interface SelectedCountry {
  country: string;
  name: string;
  value: number;
  color: string;
  description: string;
}

const Earth: React.FC = () => {
  const containerRef = useRef<HTMLDivElement>(null);
  const rendererRef = useRef<THREE.WebGLRenderer | null>(null);
  const sceneRef = useRef<THREE.Scene | null>(null);
  const cameraRef = useRef<THREE.PerspectiveCamera | null>(null);
  const earthRef = useRef<THREE.Mesh | null>(null);
  const cloudsRef = useRef<THREE.Mesh | null>(null);
  const controlsRef = useRef<OrbitControls | null>(null);
  const markersRef = useRef<THREE.Object3D[]>([]);
  const labelsRef = useRef<HTMLDivElement[]>([]);
  const raycasterRef = useRef<THREE.Raycaster>(new THREE.Raycaster());
  const mouseRef = useRef<THREE.Vector2>(new THREE.Vector2());
  
  const [selectedCountry, setSelectedCountry] = useState<SelectedCountry | null>(null);
  
  // State for marker data with values that update
  const [markers, setMarkers] = useState<Marker[]>([
    { 
      lat: 35.8617, 
      lng: 104.1954, 
      size: 0.12, 
      color: '#ff5555', 
      name: '北京', 
      country: '中国', 
      value: 8500,
      description: '中国是世界上人口最多的国家，拥有悠久的历史和文化。作为世界第二大经济体，中国在全球贸易和科技领域发挥着重要作用。'
    },
    { 
      lat: 37.0902, 
      lng: -95.7129, 
      size: 0.12, 
      color: '#55aaff', 
      name: '华盛顿', 
      country: '美国', 
      value: 7200,
      description: '美国是世界上最大的经济体，在科技、军事和文化等方面具有全球影响力。作为一个多元文化国家，美国拥有丰富的自然资源和发达的工业体系。'
    },
    { 
      lat: 61.5240, 
      lng: 105.3188, 
      size: 0.12, 
      color: '#ffaa55', 
      name: '莫斯科', 
      country: '俄罗斯', 
      value: 6300,
      description: '俄罗斯是世界上面积最大的国家，横跨欧亚大陆。拥有丰富的自然资源，尤其是石油和天然气。俄罗斯在国际政治中扮演着重要角色。'
    }
  ]);
  
  // Update marker values periodically
  useEffect(() => {
    const timer = setInterval(() => {
      setMarkers(prevMarkers => 
        prevMarkers.map(marker => ({
          ...marker,
          value: Math.max(1000, marker.value + Math.floor(Math.random() * 200 - 100))
        }))
      );
    }, 2000);
    
    return () => {
      clearInterval(timer);
    };
  }, []);
  
  const initThree = () => {
    if (!containerRef.current) return;
    
    // Create scene
    const scene = new THREE.Scene();
    scene.background = new THREE.Color(0x000000);
    sceneRef.current = scene;
    
    // Create camera
    const camera = new THREE.PerspectiveCamera(
      45,
      containerRef.current.clientWidth / containerRef.current.clientHeight,
      0.1,
      1000
    );
    camera.position.z = 6;
    cameraRef.current = camera;
    
    // Create renderer with post-processing
    const renderer = new THREE.WebGLRenderer({ 
      antialias: true,
      canvas: containerRef.current.querySelector('canvas') as HTMLCanvasElement
    });
    renderer.setSize(containerRef.current.clientWidth, containerRef.current.clientHeight);
    renderer.setPixelRatio(window.devicePixelRatio);
    rendererRef.current = renderer;

    // Add orbit controls
    const controls = new OrbitControls(camera, renderer.domElement);
    controls.enableDamping = true;
    controls.dampingFactor = 0.05;
    controls.rotateSpeed = 0.5;
    controls.minDistance = 4;
    controls.maxDistance = 10;
    controlsRef.current = controls;
    
    // Lighting
    const ambientLight = new THREE.AmbientLight(0x404040, 1);
    scene.add(ambientLight);
    
    const sunLight = new THREE.DirectionalLight(0xffffff, 2);
    sunLight.position.set(-10, 2, 10);
    scene.add(sunLight);
    
    // Load textures
    const textureLoader = new THREE.TextureLoader();
    
    // Earth
    const earthGeometry = new THREE.SphereGeometry(2, 64, 64);
    const earthMaterial = new THREE.MeshPhongMaterial({
      map: textureLoader.load('/assets/earth-texture.jpg'),
      bumpMap: textureLoader.load('/assets/earth-normal.jpg'),
      bumpScale: 0.05,
      specularMap: textureLoader.load('/assets/earth-specular.jpg'),
      specular: new THREE.Color(0x333333),
      shininess: 25
    });
    
    const earth = new THREE.Mesh(earthGeometry, earthMaterial);
    earthRef.current = earth;
    scene.add(earth);
    
    // Clouds
    const cloudsGeometry = new THREE.SphereGeometry(2.05, 64, 64);
    const cloudsMaterial = new THREE.MeshPhongMaterial({
      map: textureLoader.load('/assets/earth-clouds.jpg'),
      transparent: true,
      opacity: 0.4
    });
    
    const clouds = new THREE.Mesh(cloudsGeometry, cloudsMaterial);
    cloudsRef.current = clouds;
    scene.add(clouds);

    // Add atmosphere glow
    const atmosphereGeometry = new THREE.SphereGeometry(2.1, 64, 64);
    const atmosphereMaterial = new THREE.ShaderMaterial({
      vertexShader: `
        varying vec3 vNormal;
        void main() {
          vNormal = normalize(normalMatrix * normal);
          gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
        }
      `,
      fragmentShader: `
        varying vec3 vNormal;
        void main() {
          float intensity = pow(0.7 - dot(vNormal, vec3(0.0, 0.0, 1.0)), 2.0);
          gl_FragColor = vec4(0.3, 0.6, 1.0, 1.0) * intensity;
        }
      `,
      blending: THREE.AdditiveBlending,
      side: THREE.BackSide,
      transparent: true
    });

    const atmosphere = new THREE.Mesh(atmosphereGeometry, atmosphereMaterial);
    scene.add(atmosphere);

    // Add rings
    const addRings = () => {
      const ringCount = 3;
      const baseRadius = 3;
      const radiusStep = 0.3;
      const baseColor = new THREE.Color(0x00ffff);
      
      for (let i = 0; i < ringCount; i++) {
        const radius = baseRadius + i * radiusStep;
        const segments = 128;
        const ringGeometry = new THREE.RingGeometry(radius, radius + 0.05, segments);
        const ringMaterial = new THREE.MeshBasicMaterial({
          color: baseColor,
          transparent: true,
          opacity: 0.3 - (i * 0.1),
          side: THREE.DoubleSide,
          blending: THREE.AdditiveBlending
        });
        
        const ring = new THREE.Mesh(ringGeometry, ringMaterial);
        ring.rotation.x = Math.PI / 2;
        ring.rotation.y = Math.random() * Math.PI * 2;
        scene.add(ring);

        // Animate ring rotation
        const animate = () => {
          ring.rotation.z += 0.001 * (1 - i * 0.2);
          requestAnimationFrame(animate);
        };
        animate();
      }
    };

    addRings();
    
    // Stars
    const starsGeometry = new THREE.BufferGeometry();
    const starsCount = 2000;
    const starsPositions = new Float32Array(starsCount * 3);
    
    for (let i = 0; i < starsCount * 3; i += 3) {
      const radius = 100;
      const theta = Math.random() * Math.PI * 2;
      const phi = Math.random() * Math.PI;
      
      starsPositions[i] = radius * Math.sin(phi) * Math.cos(theta);
      starsPositions[i + 1] = radius * Math.sin(phi) * Math.sin(theta);
      starsPositions[i + 2] = radius * Math.cos(phi);
    }
    
    starsGeometry.setAttribute('position', new THREE.BufferAttribute(starsPositions, 3));
    
    const starsMaterial = new THREE.PointsMaterial({
      color: 0xffffff,
      size: 0.1,
      sizeAttenuation: true
    });
    
    const stars = new THREE.Points(starsGeometry, starsMaterial);
    scene.add(stars);
    
    // Add markers
    addMarkers();
    
    // Animation loop
    const animate = () => {
      requestAnimationFrame(animate);
      
      if (earthRef.current && cloudsRef.current && controlsRef.current) {
        earthRef.current.rotation.y += 0.0005;
        cloudsRef.current.rotation.y += 0.0007;
        controlsRef.current.update();
      }
      
      updateMarkerLabels();
      renderer.render(scene, camera);
    };
    
    animate();

    // Add window resize handler
    window.addEventListener('resize', handleResize);
    renderer.domElement.addEventListener('click', handleCanvasClick);
  };
  
  const handleCanvasClick = (event: MouseEvent) => {
    if (!containerRef.current || !cameraRef.current || !sceneRef.current) return;
    
    // Calculate mouse position in normalized device coordinates
    const rect = containerRef.current.getBoundingClientRect();
    mouseRef.current.x = ((event.clientX - rect.left) / containerRef.current.clientWidth) * 2 - 1;
    mouseRef.current.y = -((event.clientY - rect.top) / containerRef.current.clientHeight) * 2 + 1;
    
    // Update the picking ray with the camera and mouse position
    raycasterRef.current.setFromCamera(mouseRef.current, cameraRef.current);
    
    // Calculate objects intersecting the picking ray
    const intersects = raycasterRef.current.intersectObjects(markersRef.current);
    
    if (intersects.length > 0) {
      // Find which marker was clicked
      const clickedMarkerIndex = markersRef.current.findIndex(marker => marker === intersects[0].object);
      
      if (clickedMarkerIndex !== -1 && clickedMarkerIndex < markers.length) {
        const marker = markers[clickedMarkerIndex];
        setSelectedCountry({
          country: marker.country,
          name: marker.name,
          value: marker.value,
          color: marker.color,
          description: marker.description
        });
      }
    }
  };
  
  const addMarkers = () => {
    if (!sceneRef.current || !earthRef.current || !containerRef.current) return;
    
    // Clear existing labels
    labelsRef.current.forEach(label => {
      if (label.parentNode) {
        label.parentNode.removeChild(label);
      }
    });
    labelsRef.current = [];
    
    // Clear existing markers
    markersRef.current.forEach(marker => {
      if (marker.parent) {
        marker.parent.remove(marker);
      }
    });
    markersRef.current = [];
    
    markers.forEach(marker => {
      // Convert lat/lng to 3D position
      const position = latLngToVector3(marker.lat, marker.lng, 2.1);
      
      // Create marker
      const markerGeometry = new THREE.SphereGeometry(marker.size, 16, 16);
      const markerMaterial = new THREE.MeshBasicMaterial({
        color: marker.color,
        transparent: true,
        opacity: 0.9
      });
      
      const markerMesh = new THREE.Mesh(markerGeometry, markerMaterial);
      markerMesh.position.set(position.x, position.y, position.z);
      
      // Add glow effect
      const glowGeometry = new THREE.SphereGeometry(marker.size * 1.8, 16, 16);
      const glowMaterial = new THREE.MeshBasicMaterial({
        color: marker.color,
        transparent: true,
        opacity: 0.4
      });
      
      const glowMesh = new THREE.Mesh(glowGeometry, glowMaterial);
      markerMesh.add(glowMesh);
      
      // Add pulse animation
      const pulseGeometry = new THREE.SphereGeometry(marker.size * 2.5, 16, 16);
      const pulseMaterial = new THREE.MeshBasicMaterial({
        color: marker.color,
        transparent: true,
        opacity: 0.15
      });
      
      const pulseMesh = new THREE.Mesh(pulseGeometry, pulseMaterial);
      markerMesh.add(pulseMesh);
      
      // Animate pulse
      const animatePulse = () => {
        if (pulseMesh) {
          pulseMesh.scale.x = 1 + 0.2 * Math.sin(Date.now() * 0.003);
          pulseMesh.scale.y = 1 + 0.2 * Math.sin(Date.now() * 0.003);
          pulseMesh.scale.z = 1 + 0.2 * Math.sin(Date.now() * 0.003);
          requestAnimationFrame(animatePulse);
        }
      };
      animatePulse();
      
      // Add marker to Earth instead of scene so it rotates with the Earth
      if (earthRef.current) {
        earthRef.current.add(markerMesh);
        markersRef.current.push(markerMesh);
        
        // Create label
        const label = document.createElement('div');
        label.className = 'marker-label';
        label.innerHTML = `
          <div style="text-align: center;">
            <strong style="font-size: 16px; color: #ffffff;">${marker.country}</strong>
            <div style="font-size: 14px; color: #00ffff;">${marker.name}</div>
            <div style="margin-top: 5px; font-size: 18px; color: ${marker.color}; font-weight: bold;">
              ${marker.value.toLocaleString()}
            </div>
          </div>
        `;
        label.style.color = '#00ffff';
        label.style.padding = '8px 12px';
        label.style.background = 'rgba(0, 40, 70, 0.85)';
        label.style.borderRadius = '5px';
        label.style.pointerEvents = 'none';
        label.style.whiteSpace = 'nowrap';
        label.style.position = 'absolute';
        label.style.transform = 'translate(-50%, -130%)';
        label.style.border = '1px solid rgba(0, 255, 255, 0.5)';
        label.style.display = 'none'; // Initially hidden
        label.style.minWidth = '120px';
        label.style.boxShadow = '0 0 10px rgba(0, 255, 255, 0.3)';
        label.style.zIndex = '100';
        
        if (containerRef.current) {
          containerRef.current.appendChild(label);
          labelsRef.current.push(label);
        }
      }
    });
  };
  
  const updateMarkerLabels = () => {
    if (!containerRef.current || !cameraRef.current || !rendererRef.current) return;
    
    markersRef.current.forEach((marker, index) => {
      if (index < labelsRef.current.length && index < markers.length) {
        const label = labelsRef.current[index];
        
        // Get marker position in screen space
        const position = marker.getWorldPosition(new THREE.Vector3());
        const vector = position.clone().project(cameraRef.current!);
        
        // Convert to screen coordinates
        const x = (vector.x * 0.5 + 0.5) * containerRef.current!.clientWidth;
        const y = (-(vector.y * 0.5) + 0.5) * containerRef.current!.clientHeight;
        
        // Check if marker is facing the camera
        const isFacing = position.clone().normalize().dot(cameraRef.current!.position.clone().normalize()) > 0;
        
        // Update label position
        label.style.left = `${x}px`;
        label.style.top = `${y}px`;
        label.style.display = isFacing ? 'block' : 'none';
        
        // Update value in the label
        const valueElement = label.querySelector('div > div:last-child');
        if (valueElement) {
          valueElement.textContent = markers[index].value.toLocaleString();
        }
      }
    });
  };
  
  // Helper function to convert latitude and longitude to 3D position
  const latLngToVector3 = (lat: number, lng: number, radius: number): THREE.Vector3 => {
    const phi = (90 - lat) * (Math.PI / 180);
    const theta = (lng + 180) * (Math.PI / 180);
    
    const x = -radius * Math.sin(phi) * Math.cos(theta);
    const y = radius * Math.cos(phi);
    const z = radius * Math.sin(phi) * Math.sin(theta);
    
    return new THREE.Vector3(x, y, z);
  };
  
  // Re-add markers when marker data changes
  useEffect(() => {
    if (sceneRef.current && earthRef.current && containerRef.current) {
      addMarkers();
    }
  }, [markers]); // eslint-disable-line react-hooks/exhaustive-deps
  
  useEffect(() => {
    initThree();

    // Cleanup function
    return () => {
      // Dispose resources
      if (rendererRef.current) {
        rendererRef.current.dispose();
      }

      if (earthRef.current) {
        earthRef.current.geometry.dispose();
        (earthRef.current.material as THREE.Material).dispose();
      }

      if (cloudsRef.current) {
        cloudsRef.current.geometry.dispose();
        (cloudsRef.current.material as THREE.Material).dispose();
      }

      // Remove all markers
      markersRef.current.forEach(marker => {
        if (marker instanceof THREE.Mesh) {
          marker.geometry.dispose();
          (marker.material as THREE.Material).dispose();
        }
      });

      // Clear the scene
      if (sceneRef.current) {
        sceneRef.current.clear();
      }

      // Remove event listeners
      window.removeEventListener('resize', handleResize);
      if (rendererRef.current) {
        rendererRef.current.domElement.removeEventListener('click', handleCanvasClick);
      }
    };
  }, []);

  const handleResize = () => {
    if (!containerRef.current || !cameraRef.current || !rendererRef.current) return;
    
    const width = containerRef.current.clientWidth;
    const height = containerRef.current.clientHeight;
    
    cameraRef.current.aspect = width / height;
    cameraRef.current.updateProjectionMatrix();
    
    rendererRef.current.setSize(width, height);
  };

  return (
    <EarthContainer ref={containerRef}>
      <Canvas />
      {selectedCountry && (
        <CountryInfoPanel>
          <CountryTitle>{selectedCountry.country}</CountryTitle>
          <CountryInfo>
            <div>{selectedCountry.description}</div>
            <CountryValue color={selectedCountry.color}>
              {selectedCountry.value.toLocaleString()}
            </CountryValue>
          </CountryInfo>
          <CloseButton onClick={() => setSelectedCountry(null)}>关闭</CloseButton>
        </CountryInfoPanel>
      )}
    </EarthContainer>
  );
};

export default Earth; 